package pv;

/**
 * 读者 - 写者
 * <p>
 * 允许多个读者读数据, 但只允许一个写者写数据
 * 互斥关系：读者 - 写者、写者 - 写者
 * </p>
 * <p>
 * 由于可以允许多个读者进程读数据, 所以需要一个 count 来记录当前正在读的读者进程的数量
 * 可能会有多个读者进程访问 count, 所以 count 是临界资源, 多个进程需要互斥访问
 * </p>
 * <p>
 * 使用计数器 count 来记录读进程数, 通过它来判断当前进入的进程是否是第一个/最后一个进程, <b style="color: red">从而做出不同的处理</b>
 * </p>
 *
 * @author yezh
 * @date 2024/7/8 14:48
 */
public class ReaderAWriter {

    public static void main(String[] args) {
        new SleepLoopThread(ReaderAWriter::reader, 1, 2, "reader1").start();
        new SleepLoopThread(ReaderAWriter::reader, 1, 2, "reader2").start();
        new SleepLoopThread(ReaderAWriter::reader, 1, 2, "reader3").start();
        new SleepLoopThread(ReaderAWriter::write, 1, 2, "writer1").start();
        new SleepLoopThread(ReaderAWriter::write, 1, 2, "writer2").start();
        new SleepLoopThread(ReaderAWriter::write, 1, 2, "writer3").start();
    }

    /**
     * 读者的数量
     */
    private static int count = 0;

    private static final Semaphore MUTEX = new Semaphore(1, "MUTEX");
    private static final Semaphore RW = new Semaphore(1, "RW");
    /**
     * 实现读写公平
     */
    private static final Semaphore W = new Semaphore(1, "W");

//    private static final Semaphore MUTEX = new Semaphore(1);
//    private static final Semaphore RW = new Semaphore(1);

//    private static void reader() {
//        MUTEX.acquireUninterruptibly();
//        ++count;
//        if (count == 1) RW.acquireUninterruptibly();
//        MUTEX.release();
//
//        System.out.println("读者读数据");
//
//        MUTEX.acquireUninterruptibly();
//        --count;
//        if (count == 0) RW.release();
//        MUTEX.release();
//    }
//
//    private static void write() {
//        RW.acquireUninterruptibly();
//        System.out.println("写者写数据");
//        RW.release();
//    }

    private static void reader() {
        W.p();
        MUTEX.p();
        ++count;
        if (count == 1) RW.p();
        MUTEX.v();
        W.v();

        System.out.println("读者读数据");

        MUTEX.p();
        --count;
        if (count == 0) RW.v();
        MUTEX.v();
    }

    private static void write() {
        W.p();
        RW.p();
        System.out.println("写者写数据");
        RW.v();
        W.v();
    }

}
